//package com.redstar.interesting.common.starter.config;
//
//import org.apache.dubbo.config.annotation.DubboReference;
//import org.apache.dubbo.config.annotation.Reference;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.BeansException;
//import org.springframework.beans.factory.BeanFactory;
//import org.springframework.beans.factory.BeanFactoryAware;
//import org.springframework.beans.factory.FactoryBean;
//import org.springframework.beans.factory.InitializingBean;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
//import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
//import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
//import org.springframework.beans.factory.support.RootBeanDefinition;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.core.BridgeMethodResolver;
//import org.springframework.core.annotation.AnnotatedElementUtils;
//import org.springframework.core.annotation.AnnotationAttributes;
//import org.springframework.util.ClassUtils;
//import org.springframework.util.ReflectionUtils;
//
//import javax.annotation.Resource;
//import java.lang.annotation.Annotation;
//import java.lang.reflect.Field;
//import java.lang.reflect.Method;
//import java.lang.reflect.Modifier;
//import java.util.HashSet;
//import java.util.LinkedHashSet;
//import java.util.Map;
//import java.util.Set;
//import java.util.concurrent.ConcurrentHashMap;
//
//
///**
// * @author lihongxing
// */
////@Configuration
//public class InterestingBeanFactoryPostProcessor implements BeanFactoryPostProcessor, MergedBeanDefinitionPostProcessor, BeanFactoryAware {
//
//    private final Logger logger = LoggerFactory.getLogger(getClass());
//
//    private final Set<Class<? extends Annotation>> referenceAnnotationTypes = new LinkedHashSet<>(4);
//    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
//
//    private Map<String,Set<String>> referenceIdToBeanNames = new ConcurrentHashMap<>(256);
//    private Map<String,Boolean> referenceHasInit = new ConcurrentHashMap<>(256);
//
//
//    private BeanFactory beanFactory;
//
//    public InterestingBeanFactoryPostProcessor(){
//        this.referenceAnnotationTypes.add(DubboReference.class);
//        this.referenceAnnotationTypes.add(Reference.class);
//        this.autowiredAnnotationTypes.add(Autowired.class);
//        this.autowiredAnnotationTypes.add(Resource.class);
//        try {
//            autowiredAnnotationTypes.add((Class<? extends Annotation>)
//                    ClassUtils.forName("javax.inject.Inject", InterestingBeanFactoryPostProcessor.class.getClassLoader()));
//            logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
//        } catch (ClassNotFoundException e) {
//            // JSR-330 API not available - simply skip.
//        }
//    }
//
//    /**
//     * 在Spring 扫描完所有的BeanDefinition之后，在实例化bean之前执行，被允许覆盖或者添加bean属性
//     */
//    @Override
//    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//        // 获取到所有的bean定义
//        String[] allBeanDefinitionName = beanFactory.getBeanDefinitionNames();
//        for (String beanDefinitionName : allBeanDefinitionName) {
//            Class<?> clazz = beanFactory.getType(beanDefinitionName);
//            if (null != clazz) {
//                //构建源数据
//                buildReferenceMetadata(clazz, beanDefinitionName);
//            }else {
//                logger.debug(beanDefinitionName + " class not found");
//            }
//        }
//    }
//
//    private void buildReferenceMetadata(Class<?> clazz, String beanDefinitionName) {
//        findOrInjectAnnotation(clazz, (FindCallback)this::cacheReference, beanDefinitionName, referenceAnnotationTypes, DubboReference.class.getName());
//    }
//
//    private void findOrInjectAnnotation(Class<?> targetClass, CallBack callBack, String beanDefinitionName, Set<Class<? extends Annotation>> annotationTypes, String type) {
//        do {
//            ReflectionUtils.doWithLocalFields(targetClass,field -> {
//                AnnotationAttributes annotationAttributes = findAnnotation(field,annotationTypes);
//                if (null != annotationAttributes) {
//                    if (Modifier.isStatic(field.getModifiers())) {
//                        logger.info(type + " is not supported on static fields: " + field);
//                        return;
//                    }
//                }
//                String name = field.getType().getName();
//                callBack.callback(name, beanDefinitionName);
//            });
//
//            Class<?> finalTargetClass = targetClass;
//
//            ReflectionUtils.doWithLocalMethods(targetClass,method -> {
//                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
//                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
//                    return;
//                }
//                if (method.getParameterCount() == 0) {
//                    if (logger.isInfoEnabled()) {
//                        logger.info(type + "annotation should only be used on methods with parameters:" + method);
//                    }
//                    return;
//                }
//                Class<?>[] parameterTypes = method.getParameterTypes();
//                for (Class<?> parameterType : parameterTypes) {
//                    String parameterTypeName = parameterType.getName();
//                    callBack.callback(parameterTypeName, beanDefinitionName);
//                }
//            });
//            targetClass = targetClass.getSuperclass();
//        } while (targetClass != null && targetClass != Object.class);
//    }
//
//
//    //找到字段或方法上的注解
//    private AnnotationAttributes findAnnotation(Field field, Set<Class<? extends Annotation>> annotationTypes) {
//        if (field.getAnnotations().length < 1) {
//            return null;
//        }
//        for (Class<? extends Annotation> annotationType : annotationTypes) {
//            AnnotationAttributes annotationAttributes = AnnotatedElementUtils.getMergedAnnotationAttributes(field, annotationType);
//            if (annotationAttributes != null) {
//                return annotationAttributes;
//            }
//        }
//        return null;
//    }
//
//    /**
//     * Callback that supplies the owning factory to a bean instance.
//     * <p>Invoked after the population of normal bean properties
//     * but before an initialization callback such as
//     * {@link InitializingBean#afterPropertiesSet()} or a custom init-method.
//     *
//     * @param beanFactory owning BeanFactory (never {@code null}).
//     *                    The bean can immediately call methods on the factory.
//     * @throws BeansException in case of initialization errors
//     */
//    @Override
//    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
//        if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
//            throw new IllegalArgumentException("InterestingBeanFactoryPostProcessor requires a ConfigurableListableBeanFactory:" + beanFactory);
//        }
//        this.beanFactory = beanFactory;
//    }
//
//
//
//    /**
//     * Post-process the given merged bean definition for the specified bean.
//     * 在Spring 对每个类的@Autowired执行前夕，在 postProcessMergedBeanDefinition 方法，先将对应的 配置类 初始化（执行getBean）
//     *
//     * @param beanDefinition the merged bean definition for the bean
//     * @param beanType       the actual type of the managed bean instance
//     * @param beanName       the name of the bean
//     * @see AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
//     */
//    @Override
//    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//        initReference(beanType, beanName);
//    }
//
//    private void initReference(Class<?> beanType, String beanName) {
//        findOrInjectAnnotation(beanType, (InjectCallback) this::doInitReference, beanName, this.autowiredAnnotationTypes, Autowired.class.getName());
//    }
//
//    private void cacheReference(String name, String beanDefinitionName) {
//        Set<String> beanNames = referenceIdToBeanNames.get(name);
//        if (null == beanNames) {
//            beanNames = new HashSet<>();
//            referenceHasInit.put(name, Boolean.FALSE);
//        }
//        beanNames.add(beanDefinitionName);
//        referenceIdToBeanNames.put(name, beanNames);
//    }
//
//    private void doInitReference(String name, String beanName) {
//        if (Boolean.TRUE.equals(referenceHasInit.get(name)) || !this.referenceIdToBeanNames.containsKey(name)) {
//            return;
//        }
//        Set<String> beanNames = referenceIdToBeanNames.get(name);
//        if (beanNames.contains(beanName)) {
//            referenceHasInit.put(name, Boolean.TRUE);
//        }
//        beanNames.forEach(b -> beanFactory.getBean(b));
//        referenceHasInit.put(name, Boolean.TRUE);
//
//    }
//
//    /**
//     * A notification that the bean definition for the specified name has been reset,
//     * and that this post-processor should clear any metadata for the affected bean.
//     * <p>The default implementation is empty.
//     *
//     * @param beanName the name of the bean
//     * @see DefaultListableBeanFactory#resetBeanDefinition
//     * @since 5.1
//     */
//    @Override
//    public void resetBeanDefinition(String beanName) {
//        MergedBeanDefinitionPostProcessor.super.resetBeanDefinition(beanName);
//    }
//
//
//
//
//
//
//
//    /**
//     * Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
//     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
//     * or a custom init-method). The bean will already be populated with property values.
//     * The returned bean instance may be a wrapper around the original.
//     * <p>The default implementation returns the given {@code bean} as-is.
//     *
//     * @param bean     the new bean instance
//     * @param beanName the name of the bean
//     * @return the bean instance to use, either the original or a wrapped one;
//     * if {@code null}, no subsequent BeanPostProcessors will be invoked
//     * @throws BeansException in case of errors
//     * @see InitializingBean#afterPropertiesSet
//     */
//    @Override
//    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//        return bean;
//    }
//
//    /**
//     * Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
//     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
//     * or a custom init-method). The bean will already be populated with property values.
//     * The returned bean instance may be a wrapper around the original.
//     * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
//     * instance and the objects created by the FactoryBean (as of Spring 2.0). The
//     * post-processor can decide whether to apply to either the FactoryBean or created
//     * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
//     * <p>This callback will also be invoked after a short-circuiting triggered by a
//     * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
//     * in contrast to all other {@code BeanPostProcessor} callbacks.
//     * <p>The default implementation returns the given {@code bean} as-is.
//     *
//     * @param bean     the new bean instance
//     * @param beanName the name of the bean
//     * @return the bean instance to use, either the original or a wrapped one;
//     * if {@code null}, no subsequent BeanPostProcessors will be invoked
//     * @throws BeansException in case of errors
//     * @see InitializingBean#afterPropertiesSet
//     * @see FactoryBean
//     */
//    @Override
//    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//        return bean;
//    }
//
//
//
//
//    interface CallBack{
//        void callback(String name, String beanName);
//    }
//
//    interface FindCallback extends CallBack{
//
//    }
//    interface InjectCallback extends CallBack{
//
//    }
//
//
//}
